package config

import (
	"fmt"
	"github.com/go-redis/redis/v8"
	"github.com/spf13/viper"
	"log"
	"os"
	"strings"
	"vben-common/logs"
)

var C = InitConfig()

type Config struct {
	viper       *viper.Viper
	SC          *ServerConfig
	GC          *GrpcConfig
	EtcdConfig  *EtcdConfig
	MysqlConfig *MysqlConfig
	LogConfig   *LogConfig
	AppMode     string
	BasePath    string
}

type ServerConfig struct {
	Name string
	Addr string
}

type GrpcConfig struct {
	Name    string
	Addr    string
	Version string
	Weight  int64
}

type EtcdConfig struct {
	Addrs []string
}

type MysqlConfig struct {
	Host     string
	Port     string
	Username string
	Password string
	Dsn      string
	Db       string
}

type LogConfig struct {
	GinLogName        string
	GoSkeletonLogName string
	TextFormat        string
	TimePrecision     string
	MaxSize           int64
	MaxBackups        int64
	MaxAge            int64
	Compress          bool
}

func InitConfig() *Config {
	conf := &Config{
		viper: viper.New(),
	}
	workDir, _ := os.Getwd()
	conf.viper.SetConfigName("app")
	conf.viper.SetConfigType("yaml")
	conf.viper.AddConfigPath("/etc/ms_project/user")
	conf.viper.AddConfigPath(workDir + "/config")
	err := conf.viper.ReadInConfig()
	if err != nil {
		log.Fatalln(err)
	}
	// 设置程序所处的模式, 默认为开发模式 (debug), release, test, prod
	// 调试模式，日志优先显示在控制台
	conf.AppMode = conf.viper.GetString("app.appMode")
	conf.InitBasePath()
	conf.ReadServerConfig()
	conf.InitZapLog()
	conf.ReadGrpcConfig()
	conf.ReadEtcdConfig()
	conf.ReadMysqlConfig()
	conf.ReadLogConfig()
	return conf
}

func (c *Config) InitBasePath() {
	// 1.初始化程序根目录
	if curPath, err := os.Getwd(); err == nil {
		// 路径进行处理，兼容单元测试程序程序启动时的奇怪路径
		if len(os.Args) > 1 && strings.HasPrefix(os.Args[1], "-test") {
			c.BasePath = strings.Replace(strings.Replace(curPath, `\test`, "", 1), `/test`, "", 1)
		} else {
			c.BasePath = curPath
		}
	}
}

func (c *Config) InitZapLog() {
	// 从配置中读取日志配置，初始化日志
	lc := &logs.LogConfig{
		DebugFileName: c.viper.GetString("zap.debugFileName"),
		InfoFileName:  c.viper.GetString("zap.infoFileName"),
		WarnFileName:  c.viper.GetString("zap.warnFileName"),
		MaxSize:       c.viper.GetInt("zap.maxSize"),
		MaxAge:        c.viper.GetInt("zap.maxAge"),
		MaxBackups:    c.viper.GetInt("zap.maxBackups"),
	}
	err := logs.InitLogger(lc)
	if err != nil {
		log.Fatalln(err)
	}
}

func (c *Config) ReadServerConfig() {
	sc := &ServerConfig{}
	sc.Name = c.viper.GetString("server.name")
	sc.Addr = c.viper.GetString("server.addr")
	c.SC = sc
}

func (c *Config) ReadGrpcConfig() {
	gc := &GrpcConfig{}
	gc.Name = c.viper.GetString("grpc.name")
	gc.Addr = c.viper.GetString("grpc.addr")
	gc.Version = c.viper.GetString("grpc.version")
	gc.Weight = c.viper.GetInt64("grpc.weight")
	c.GC = gc
}

func (c *Config) ReadRedisConfig() *redis.Options {
	return &redis.Options{
		Addr:     c.viper.GetString("redis.host") + ":" + c.viper.GetString("redis.port"),
		Password: c.viper.GetString("redis.password"),
		DB:       c.viper.GetInt("redis.db"),
	}
}

func (c *Config) ReadEtcdConfig() {
	ec := &EtcdConfig{}
	var addrs []string
	err := c.viper.UnmarshalKey("etcd.addrs", &addrs)
	if err != nil {
		log.Fatalln(err)
	}
	ec.Addrs = addrs
	c.EtcdConfig = ec
}

func (c *Config) ReadMysqlConfig() {
	mc := &MysqlConfig{}
	mc.Host = c.viper.GetString("mysql.host")
	mc.Port = c.viper.GetString("mysql.port")
	mc.Username = c.viper.GetString("mysql.username")
	mc.Password = c.viper.GetString("mysql.password")
	mc.Db = c.viper.GetString("mysql.db")
	mc.Dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=%s", mc.Username, mc.Password, mc.Host, mc.Port, mc.Db, "Asia%2FShanghai")
	c.MysqlConfig = mc
}

func (c *Config) ReadLogConfig() {
	lc := &LogConfig{}
	lc.GinLogName = c.viper.GetString("logs.ginLogName")
	lc.GoSkeletonLogName = c.viper.GetString("logs.goSkeletonLogName")
	lc.TextFormat = c.viper.GetString("logs.textFormat")
	lc.TimePrecision = c.viper.GetString("logs.timePrecision")
	lc.MaxSize = c.viper.GetInt64("logs.maxSize")
	lc.MaxBackups = c.viper.GetInt64("logs.maxBackups")
	lc.MaxAge = c.viper.GetInt64("logs.maxAge")
	lc.Compress = c.viper.GetBool("logs.compress")
	c.LogConfig = lc
}
